package com.cloud.animationtestdemo.widget

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.RectF
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import android.util.AttributeSet
import android.view.KeyEvent
import androidx.appcompat.widget.AppCompatImageView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import android.graphics.*
/**
 * @author: njb
 * @date:   2025/3/2 23:32
 * @desc:   描述
 */
class BigImageView  @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : AppCompatImageView(context, attrs, defStyle), Parcelable {

    private var loader: BigImageLoader? = null
    private var loaderJob: Job? = null
    private val matrix = Matrix()
    private val viewRect = Rect()
    private val imageRect = RectF()
    private val tileMap = mutableMapOf<BigImageLoader.Tile, Bitmap>()
    private var currentScale = 1.0f
    private var maxScale = 8.0f
    private var minScale = 0.5f
    private var isInitialized = false

    private val scrollSpeed = 150f
    private var velocityX = 0f
    private var velocityY = 0f
    private val animator = ValueAnimator()

    constructor(parcel: Parcel) : this(
        TODO("context"),
        TODO("attrs"),
        TODO("defStyle")
    ) {
        currentScale = parcel.readFloat()
        maxScale = parcel.readFloat()
        minScale = parcel.readFloat()
        isInitialized = parcel.readByte() != 0.toByte()
        velocityX = parcel.readFloat()
        velocityY = parcel.readFloat()
    }

    init {
        scaleType = ScaleType.MATRIX
        isFocusable = true
        isFocusableInTouchMode = true
    }

    fun loadImage(uri: Uri) {
        loader?.release()
        loader = BigImageLoader(context).apply {
            loaderJob = CoroutineScope(Dispatchers.Main).launch {
                loadImage(uri).collect { tile ->
                    tileMap[tile.tile] = tile.bitmap
                    invalidate()
                }
            }
        }
        requestFocus()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        viewRect.set(0, 0, measuredWidth, measuredHeight)
        updateVisibleRect()
    }

    override fun onDraw(canvas: Canvas) {
        if (!isInitialized) return

        val matrixValues = FloatArray(9)
        matrix.getValues(matrixValues)
        val transX = matrixValues[Matrix.MTRANS_X]
        val transY = matrixValues[Matrix.MTRANS_Y]
        val scale = matrixValues[Matrix.MSCALE_X]

        tileMap.forEach { (tile, bitmap) ->
            val tileSize = (bitmap.width / scale).toInt()
            val left = tile.x * tileSize
            val top = tile.y * tileSize
            val right = left + tileSize
            val bottom = top + tileSize

            if (Rect(left, top, right, bottom).intersect(viewRect)) {
                val srcRect = Rect(0, 0, bitmap.width, bitmap.height)
                val dstRect = RectF(
                    left * scale + transX,
                    top * scale + transY,
                    right * scale + transX,
                    bottom * scale + transY
                )
                canvas.drawBitmap(bitmap, srcRect, dstRect, null)
            }
        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        when (keyCode) {
            KeyEvent.KEYCODE_DPAD_LEFT -> velocityX = -scrollSpeed
            KeyEvent.KEYCODE_DPAD_RIGHT -> velocityX = scrollSpeed
            KeyEvent.KEYCODE_DPAD_UP -> velocityY = -scrollSpeed
            KeyEvent.KEYCODE_DPAD_DOWN -> velocityY = scrollSpeed
            KeyEvent.KEYCODE_ZOOM_IN -> zoom(1.25f)
            KeyEvent.KEYCODE_ZOOM_OUT -> zoom(0.8f)
            else -> return super.onKeyDown(keyCode, event)
        }
        startAutoScroll()
        return true
    }

    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
        when (keyCode) {
            KeyEvent.KEYCODE_DPAD_LEFT,
            KeyEvent.KEYCODE_DPAD_RIGHT,
            KeyEvent.KEYCODE_DPAD_UP,
            KeyEvent.KEYCODE_DPAD_DOWN -> stopAutoScroll()
        }
        return super.onKeyUp(keyCode, event)
    }

    private fun zoom(factor: Float) {
        currentScale = (currentScale * factor).coerceIn(minScale, maxScale)
        matrix.postScale(factor, factor, viewRect.centerX().toFloat(), viewRect.centerY().toFloat())
        adjustPosition()
        loader?.updateScale(currentScale)
        updateVisibleRect()
        invalidate()
    }

    private fun startAutoScroll() {
        animator.cancel()
        animator.apply {
            setFloatValues(0f, 1f)
            duration = 1000
            addUpdateListener {
                val deltaX = velocityX * it.animatedFraction
                val deltaY = velocityY * it.animatedFraction
                matrix.postTranslate(deltaX, deltaY)
                adjustPosition()
                updateVisibleRect()
                invalidate()
            }
            start()
        }
    }

    private fun stopAutoScroll() {
        velocityX = 0f
        velocityY = 0f
        animator.cancel()
    }

    private fun adjustPosition() {
        val matrixValues = FloatArray(9)
        matrix.getValues(matrixValues) // 获取矩阵参数
        val transX = matrixValues[Matrix.MTRANS_X]
        val transY = matrixValues[Matrix.MTRANS_Y]

        val imageRect = getImageRect()
        val viewRect = RectF(viewRect)

        // 水平方向调整
        if (imageRect.width() <= viewRect.width()) {
            matrix.postTranslate(
                viewRect.centerX() - imageRect.centerX() - transX, // 使用实际平移值
                0f
            )
        } else {
            if (imageRect.left > viewRect.left) {
                matrix.postTranslate(viewRect.left - imageRect.left - transX, 0f)
            }
            if (imageRect.right < viewRect.right) {
                matrix.postTranslate(viewRect.right - imageRect.right - transX, 0f)
            }
        }

        // 垂直方向调整
        if (imageRect.height() <= viewRect.height()) {
            matrix.postTranslate(
                0f,
                viewRect.centerY() - imageRect.centerY() - transY // 使用实际平移值
            )
        } else {
            if (imageRect.top > viewRect.top) {
                matrix.postTranslate(0f, viewRect.top - imageRect.top - transY)
            }
            if (imageRect.bottom < viewRect.bottom) {
                matrix.postTranslate(0f, viewRect.bottom - imageRect.bottom - transY)
            }
        }
    }

    private fun getImageRect(): RectF {
        return RectF(0f, 0f, width.toFloat(), height.toFloat()).apply {
            matrix.mapRect(this)
        }
    }

    private fun updateVisibleRect() {
        val visibleRect = getImageRect()
        loader?.updateVisibleRect(
            Rect(
            visibleRect.left.toInt(),
            visibleRect.top.toInt(),
            visibleRect.right.toInt(),
            visibleRect.bottom.toInt()
        )
        )
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        loader?.release()
        loaderJob?.cancel()
        animator.cancel()
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeFloat(currentScale)
        parcel.writeFloat(maxScale)
        parcel.writeFloat(minScale)
        parcel.writeByte(if (isInitialized) 1 else 0)
        parcel.writeFloat(velocityX)
        parcel.writeFloat(velocityY)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<BigImageView> {
        override fun createFromParcel(parcel: Parcel): BigImageView {
            return BigImageView(parcel)
        }

        override fun newArray(size: Int): Array<BigImageView?> {
            return arrayOfNulls(size)
        }
    }
}